#!/usr/bin/python

# -*- coding: utf-8 -*-

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or (at
#  your option) any later version.
#
#  This program is distributed in the hope that it will be useful, but
#  WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
#  General Public License for more details.
#
#  You should have received a copy of the GNU General Public License along
#  with this program; if not, write to the Free Software Foundation, Inc.,
#  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

 
#from pseudovisa import *
from visa import *
from devicesconfig import *
#from threading import *
from time import *
from qt import *
 
#
# in visacontrol.py there are all classes which send commands to the instruments (over pyVisa)
# be careful with changing things in here
# 
# Classes: 	deviceStatus:	holds informations about connected devices, and the pyVisa-GpibInstrument-class
#		visaThread:	reads from the instruments, this sometimes need some time, so it's in a thread, otherwise the programm would be blocked
#		visaControl:	this is the mainclass in here, it has all function which are called from outside
#

def get_visa_instruments_list():
	return get_instruments_list()

class PseudoInstrument(object):
	
	def __init__(self, board_number=0):
		print "new pseudo-instrument"
		self.boardnumber=board_number
	
	def write(self, message):
		print "write:", message
		
	def ask(self, message):
		return message
	
	def timeout(self,msecs):
		#print "Neuer TimeOut: ",msecs
		return
		
 
class deviceStatus(object):
	def __init__(self,name,boardnumber,virtual=False,isInit=False):
		self.name=name
		self.boardnumber=str(boardnumber)
		if boardnumber.find("virtual")==-1:
			self.gpib=Instrument(self.boardnumber)
		else: 
			self.gpib=PseudoInstrument(self.boardnumber)
		self.isInitiated=isInit
		exec('self.commands='+name+'()')
	
 
class visaThread(QThread):
	def __init__(self, name, *args):
		self.name=name
        	QThread.__init__(self)
		self.mutex=QMutex()
		self.sender=QObject()
		self.gotData=False
		self.lastTime=0
		self.waitTime=200
		self.time=QTime()
		self.time.start()
		self.counter=0
		self.stop=False
		self.plotLastXValue=0
		self.plotLastYValue=0
		self.plotYValue=0
		self.plotXValue=0
		self.plotIntegral=0
		
		
	def init(self,devices):
		self.devices=devices
		self.time.restart()
		self.counter=0
		self.stop=False
		
	def mySleep(self,msec):
		starttime=self.time.elapsed()
		stoptime=starttime+msec
		while self.time.elapsed()<stoptime:
			self.msleep(50)
			if self.stop==True: break
			
		
	def run(self):
		#self.mutex.lock()
		self.gotData=False
		if self.time.elapsed()<self.waitTime:
			self.mySleep(self.waitTime-self.time.elapsed())
		self.time.restart()
		if self.stop: return
		for x in self.devices:
			#print "1 ",x.commands.typ
			if x.isInitiated==True:
				#print "2 ",x.commands.typ
				if (x.commands.typ!="w")and(x.commands.typ!="vw"):
					doRead=True
					if self.counter>0:
						if x.commands.canAveraging==False:
							doRead=False
					if doRead==True:
						x.commands.setPlotValues(self.plotLastXValue,self.plotLastYValue,self.plotYValue,self.plotXValue,self.plotIntegral)
						r=x.commands.read()
						if r[:7]=="STOPNOW":
							print "Device says stopping...stopping"
							self.stop=True
							r=r[7:]
							
						#print "3 ",x.commands.typ,r
						if len(r)>0:
							if type(r) is type(()):
								self.gotData=True
								ok=1
								while ok>0:
									raw=""
									for z in r:
										if self.stop: break
										#Repeat Reading until OK

										x.gpib.timeout=15
										r2=x.gpib.ask(z)

										if len(raw)==0:	raw=r2
										else: raw=raw+",,"+r2
										#print raw
										
									#Is data OK to continue?
									ok=x.commands.isDataOK(raw)
									if ok>0: 
										print "Sleeping ",ok
										self.mySleep(int(ok))
										
								x.commands.addRawData(raw)
							
							else:
								self.gotData=True
								ok=1
								while ok>0:
									if self.stop==True: break
									x.gpib.timeout=15
									raw=x.gpib.ask(r)
									ok=x.commands.isDataOK(raw)
									if ok>0: 
										print "Sleeping ",ok
										self.mySleep(int(ok))

								if self.stop==False:
                                                                        x.commands.addRawData(raw)
					
		self.counter+=1
		#self.mutex.unlock()
		#print "thread finished"
		#self.sender.emit(PYSIGNAL("threadEnd"),())
		 
		 
class visaControl(QObject):
	def __init__(self,parent):
		QObject.__init__(self,parent)
		self.devices=[]
		self.boardInit=[]
		self.gpibs=[]
		dev=allDevices()
		self.pos=0
		self.count=0
		self.timer = QTimer()
    		self.connect( self.timer, SIGNAL('timeout()'), self.timerEvent)
		self.stop=False
		self.thread=visaThread("visaThread")
		self.connect( self.thread.sender, PYSIGNAL('threadEnd'), self.threadEnd)
		#self.connect( self.thread, SIGNAL('newMessdaten'), PYSIGNAL('newMessdaten'))
		self.waitTime=10
		
		for x in dev.all():
			eval('self.gpibs.append('+x+'())')
			#self.gpibs[len(self.device)-1].name)
		
	def getBoardInit(self,boardnumber):
		for x in self.boardInit:
			if x==boardnumber:
				return True
		return False
		
	def findDevice(self,name,boardnumber):
		for x in self.devices:
			if x.boardnumber==str(boardnumber):
				if x.name==name:
					return x
		
		print "visacontrol: no internal device for this instrument found, creating new one:",len(self.devices)
		self.devices.append(deviceStatus(name,boardnumber))
		return self.devices[len(self.devices)-1]
		
	def writeList(self,gpib,liste):
		if self.thread.running():
			self.thread.wait()
		for x in liste:
			gpib.write(x)
	
	def doInit(self,name,boardnumber,typ,begin,mode,end,steps,force=False):
		device=self.findDevice(name,boardnumber)
		device.commands.begin=begin
		device.commands.end=end
		device.commands.steps=steps
		device.commands.mode=mode # 0=nothing 1=|... 2=-->
		#print device.commands.begin,begin,device.commands.end,end,device.commands.steps,steps
		#print "doInit"
		if device.isInitiated==False:
			#print "doInit A"
			if self.getBoardInit(boardnumber)==False:
				self.writeList(device.gpib,device.commands.getInit())
				self.boardInit.append(boardnumber)
				device.isInitiated=True
		elif force==True:
			#print "doInit B"
			self.writeList(device.gpib,device.commands.getInit())
		
	def setStepPos(self,name,boardnumber,pos):
		device=self.findDevice(name,boardnumber)
		device.commands.setStepPos(pos)
		
	def incStepPos(self,name,boardnumber,pos):
		device=self.findDevice(name,boardnumber)
		device.commands.incStepPos(pos)
		
	def getStepPos(self,name,boardnumber):
		device=self.findDevice(name,boardnumber)
		return device.commands.getStepPos()
	
	def getData(self,name,boardnumber):
		device=self.findDevice(name,boardnumber)
		return device.commands.getData()
		
	def doStep(self,name,boardnumber,pos):
		device=self.findDevice(name,boardnumber)
		step=()
		if (device.commands.typ!="r"):
			step=device.commands.getStep(pos)
		self.writeList(device.gpib,step)
		
	
	def timerEvent(self):
		if self.thread.finished():
			#print "Thread finished"
			self.threadEnd()

	def startThread(self):
		#print self.thread.gotData,self.pos,self.count
		if self.stop==True:
			self.pos=self.count
		if self.pos<self.count:
			if self.thread.running():
				self.thread.wait()
			self.thread.start()
		else: 
			self.timer.stop()
			self.emit(PYSIGNAL('newMessdaten'), ())

	def threadEnd(self):
		#print self.thread.gotData,self.pos,self.count
		if ((self.thread.stop==True)and(self.stop==False)):
			self.emit(PYSIGNAL('stopMessung'), ())
					
		if self.stop==True:
			self.pos=self.count
			
		if self.pos<self.count:
			self.pos+=1
			
		if self.thread.gotData==False:
			self.pos=self.count
			
		self.startThread() #important get last data
		
	
	#Reads number of averaging count all instruments, the emits newMessdaten
	def readAll(self,count=1):
		self.count=count
		self.pos=0
		self.thread.init(self.devices)
		self.timer.start(self.waitTime,False)
		self.startThread()

	#final commands to the instruments
	def finishAll(self):
		for x in self.devices:
			if x.isInitiated==True:
				f=x.commands.getFinish()
				for y in f:
					x.gpib.write(y)

	#init instrument again (when doInit is called with this instrument)
	def resetInit(self,waitAtLeastMs=200):
		#print "ResetInit"
		self.boardInit=[]
		self.thread.waitTime=waitAtLeastMs
		for x in self.devices:
			x.isInitiated=False
			
			
	def plotProperties(self,plotLastXValue,plotLastYValue,plotYValue,plotXValue,plotIntegral):
		self.thread.plotLastXValue=plotLastXValue
		self.thread.plotLastYValue=plotLastYValue
		self.thread.plotYValue=plotYValue
		self.thread.plotXValue=plotXValue
		self.thread.plotIntegral=plotIntegral
			

